﻿using System;
using System.Collections;
using System.Xml;
using System.Xml.Serialization;

using Gonte.Reflection;

namespace Gonte.Xml.Serialization
{
    public class XmlPrimitiveSerializer
        : XmlObjectSerializer
    {
        #region Constructors

        protected internal XmlPrimitiveSerializer(Object @object)
            : base(@object)
        {
        } 

        #endregion

        #region Overridables

        public override void Serialize(XmlWriter writer, XmlSerializationContext context)
        {
            bool saveAsElement;
            string propertyName = GetElementName(context, out saveAsElement);

            if (saveAsElement)
            {
                writer.WriteStartElement(propertyName);
                writer.WriteString(object_.ToString());
                writer.WriteEndElement();
            }
            else
            {
                writer.WriteStartAttribute(propertyName);
                writer.WriteString(object_.ToString());
                writer.WriteEndAttribute();
            }
        } 

        #endregion

        #region Helpers

        /// <summary>
        /// Retrieves the name of the element to serialize
        /// </summary>
        /// <param name="context">The serialization context</param>
        /// <param name="saveAsElement">Whether to save the primitive as an element and not as an attribute</param>
        /// <returns>The name of the element</returns>
        private string GetElementName(XmlSerializationContext context, out bool saveAsElement)
        {
            saveAsElement = false;
            if (context != null)
            {
                if (context.Attributes != null)
                {
                    XmlElementAttribute xmlElementAttribute = CustomAttribute.FindAttribute<XmlElementAttribute>(context.Attributes);
                    if (xmlElementAttribute != null
                        && !string.IsNullOrEmpty(xmlElementAttribute.ElementName))
                    {
                        saveAsElement = true;
                        return xmlElementAttribute.ElementName;
                    }

                    XmlAttributeAttribute xmlAttributeAttribute = CustomAttribute.FindAttribute<XmlAttributeAttribute>(context.Attributes);
                    if (xmlAttributeAttribute != null
                        && !string.IsNullOrEmpty(xmlAttributeAttribute.AttributeName))
                    {
                        return xmlAttributeAttribute.AttributeName;
                    }
                }

                if (context.Parent != null
                    && context.Parent is ICollection)
                {
                    saveAsElement = true; // Collection of primitives are saved as elements
                }

                if (string.IsNullOrEmpty(context.PropertyName))
                {
                    return object_.GetType().Name;
                }

                return context.PropertyName;
            }
            else
            {
                saveAsElement = true; // No context means that the primitive is the root therefore it is not an attribute of a parent object
                return object_.GetType().Name;
            }
        } 

        #endregion
    }
}
